using System;
using System.Collections.Generic;
using System.Linq;
using F8Framework.Launcher;

// 假设 MahjongTile 定义类似： public string Type; public int Value; public bool IsSpecial;
public static class RulesModule
{
    public static List<string> ParseAllowedTypes(string types)
    {
        if (string.IsNullOrWhiteSpace(types)) return new();
        return types.Split(',').Select(s => s.Trim()).Where(s => s.Length>0).ToList();
    }

    public static List<int> ParseAllowedValues(string values)
    {
        var list = new List<int>();
        if (string.IsNullOrWhiteSpace(values)) return list;

        // 支持 "1-9" 或 "1,3,5"
        if (values.Contains('-'))
        {
            var parts = values.Split('-').Select(p => p.Trim()).ToArray();
            if (parts.Length == 2 && int.TryParse(parts[0], out int a) && int.TryParse(parts[1], out int b))
            {
                for (int i = a; i <= b; i++) list.Add(i);
                return list;
            }
        }

        foreach (var part in values.Split(','))
        {
            if (int.TryParse(part.Trim(), out int v)) list.Add(v);
        }

        return list;
    }

    // 判断三张是否为顺子（同一花色，值连续）
    private static bool IsSequence(List<MahjongTile> tiles)
    {
        if (tiles.Count != 3) return false;
        if (tiles.Any(t => t.Config.Type == "Zi")) return false; // 字牌不能顺子
        var vals = tiles.Select(t => t.Config.Value).OrderBy(v => v).ToArray();
        return vals[1] == vals[0] + 1 && vals[2] == vals[1] + 1 && tiles.All(t => t.Config.Type == tiles[0].Config.Type);
    }

    // 判断若干张是否全相同（刻子 / 将 / 杠）
    private static bool AllSame(List<MahjongTile> tiles)
    {
        return tiles.Select(t => (t.Config.Type, t.Config.Value)).Distinct().Count() == 1;
    }

    // 将一组 tiles 能否分解成指定数量的「顺子或刻子」(melds) + 一个对子(pair)
    // meldCount: 2 对应你规则里的“两组顺子或刻子”
    private static bool CanFormMeldsAndPair(List<MahjongTile> tiles, int meldCount)
    {
        // tiles.Count expected = meldCount*3 + 2 (e.g., 2*3 + 2 = 8)
        if (tiles == null) return false;
        if (tiles.Count != meldCount * 3 + 2) return false;

        // 按 (Type,Value) 分组计数
        var groups = tiles.GroupBy(t => (t.Config.Type, t.Config.Value))
                          .ToDictionary(g => g.Key, g => g.Count());

        // 先枚举可能作为将的对子（任意一对）
        var candidatePairs = groups.Where(kv => kv.Value >= 2).Select(kv => kv.Key).ToList();
        foreach (var pairKey in candidatePairs)
        {
            // 克隆计数字典，减掉对子
            var counts = groups.ToDictionary(kv => kv.Key, kv => kv.Value);
            counts[pairKey] -= 2;
            if (counts[pairKey] == 0) counts.Remove(pairKey);

            // 尝试消除 meldCount 个 meld（顺或刻）
            if (TryRemoveMelds(counts, meldCount))
                return true;
        }

        return false;
    }

    // 递归尝试用 counts 中的牌凑出 countOfMelds 个 meld（顺/刻）
    private static bool TryRemoveMelds(Dictionary<(string Type,int Value), int> counts, int countOfMelds)
    {
        if (countOfMelds == 0)
        {
            // 成功消掉所需数量的 meld，剩下应该为空
            return counts.Count == 0;
        }

        if (counts.Count == 0) return false;

        // 取任意一个牌做尝试（选择最小 value 的牌可减少分支）
        var first = counts.OrderBy(kv => kv.Key.Type).ThenBy(kv => kv.Key.Value).First();
        var key = first.Key;
        int avail = first.Value;

        // 尝试刻子（count >= 3）
        if (avail >= 3)
        {
            var copy = counts.ToDictionary(kv => kv.Key, kv => kv.Value);
            copy[key] -= 3;
            if (copy[key] == 0) copy.Remove(key);
            if (TryRemoveMelds(copy, countOfMelds - 1)) return true;
        }

        // 尝试顺子（仅对非字牌有效, 并且需要 Type 相同，value+1 value+2 存在）
        if (key.Type != "Zi")
        {
            var k1 = (key.Type, key.Value + 1);
            var k2 = (key.Type, key.Value + 2);
            if (counts.ContainsKey(k1) && counts.ContainsKey(k2))
            {
                var copy = counts.ToDictionary(kv => kv.Key, kv => kv.Value);
                // 减去各1张
                DecreaseOrRemove(copy, key);
                DecreaseOrRemove(copy, k1);
                DecreaseOrRemove(copy, k2);
                if (TryRemoveMelds(copy, countOfMelds - 1)) return true;
            }
        }

        return false;
    }

    private static void DecreaseOrRemove(Dictionary<(string Type,int Value), int> dict, (string Type,int Value) k)
    {
        dict[k]--;
        if (dict[k] <= 0) dict.Remove(k);
    }

    // 主匹配函数（基于 RulesItem）
    public static bool MatchRule(F8Framework.F8ExcelDataClass.RulesItem rule, List<MahjongTile> tiles)
    {
        if (rule == null) return false;
        if (tiles == null) return false;

        // 数量先校验（绝大多数规则严格等于 RequiredCount）
        if (tiles.Count != rule.RequiredCount) return false;

        var allowedTypes = ParseAllowedTypes(rule.AllowedTypes);
        var allowedValues = ParseAllowedValues(rule.AllowedValues);

        // 检查每张牌的 type/value 是否在表允许范围内
        if (!tiles.All(t => allowedTypes.Contains(t.Config.Type))) return false;
        if (!tiles.All(t => allowedValues.Contains(t.Config.Value))) return false;

        // 如果规则需要包含特殊牌但 MahjongTile 没有 IsSpecial 字段，则无法判定（视为不匹配）
        if (rule.ContainsSpecial)
        {
            // 如果你的 MahjongTile 有 IsSpecial 字段，请打开下面的代码：
            // if (!tiles.Any(t => t.IsSpecial)) return false;
            // 当前实现：如果配置要求 ContainsSpecial，但 tile 无法表明 special，则跳过此判断或认为 false
        }

        // 单项规则判断（按你的规则表）
        // 1. 吃（RequiredCount==3 && IsSequential==true && AllowDuplicates==false）
        if (rule.RequiredCount == 3 && rule.IsSequential && !rule.AllowDuplicates)
        {
            return IsSequence(tiles);
        }

        // 2. 碰（3张相同）
        if (rule.RequiredCount == 3 && !rule.IsSequential && rule.AllowDuplicates)
        {
            return AllSame(tiles);
        }

        // 3. 杠（4张相同）
        if (rule.RequiredCount == 4 && rule.AllowDuplicates)
        {
            return AllSame(tiles);
        }

        // 4. 将（2张相同）
        if (rule.RequiredCount == 2 && rule.RequirePair)
        {
            return AllSame(tiles) && tiles.Count == 2;
        }

        // 5. 胡 / 清一色 / 混一色 / 全字 —— 都是 RequiredCount == 8 的特殊判断
        if (rule.RequiredCount == 8)
        {
            // 清一色：所有牌为同一序数花色（只在 AllowedTypes 中没有 Zi）
            if (rule.Name_CN.Contains("清一色") || (allowedTypes.All(t => t != "Zi") && rule.RequirePair))
            {
                // 所有牌类型必须是同一序数花色，且可以被分为两组 meld + 一对
                var singleSuit = tiles.Select(t => t.Config.Type).Distinct().Count() == 1 && tiles.All(t => t.Config.Type != "Zi");
                return singleSuit && CanFormMeldsAndPair(tiles, 2);
            }

            // 混一色：一类序数花色 + 字牌（必须同时包含字牌与某一序数花色）
            if (rule.Name_CN.Contains("混一色") || rule.Name_CN.Contains("混") )
            {
                var types = tiles.Select(t => t.Config.Type).Distinct().ToList();
                // 必须包含 Zi 且仅包含一个序数花色（Tong/Tiao/Wan）和 Zi
                var seqSuits = types.Where(t => t != "Zi").Distinct().ToList();
                var hasZi = types.Contains("Zi");
                if (hasZi && seqSuits.Count == 1)
                {
                    // 再确保能构成 2 meld + pair（允许含字牌）
                    return CanFormMeldsAndPair(tiles, 2);
                }
                return false;
            }

            // 全字：全部为 Zi 且能构成 2 meld + pair（这里 meld 指允许由字牌组成的刻子/风刻）
            if (rule.Name_CN.Contains("全字") || allowedTypes.Count==1 && allowedTypes.Contains("Zi"))
            {
                if (tiles.All(t => t.Config.Type == "Zi"))
                    return CanFormMeldsAndPair(tiles, 2);
                return false;
            }

            // 一般的 胡（只遵循“两组顺子或刻子 + 对将”的定义）
            if (rule.Name_CN.Contains("胡") || rule.RequirePair)
            {
                return CanFormMeldsAndPair(tiles, 2);
            }
        }

        // 若上面都没命中，尝试更通用的判定：
        // - 如果 IsSequential 且 RequiredCount==3 -> sequence
        if (rule.IsSequential && rule.RequiredCount == 3)
            return IsSequence(tiles);

        // - 如果 AllowDuplicates 且 所有相同 -> true
        if (rule.AllowDuplicates && AllSame(tiles))
            return true;

        return false;
    }

    /// <summary>
    /// 从手牌中生成所有可能的组合（从handTiles中选出count张牌）
    /// </summary>
    private static IEnumerable<List<MahjongTile>> GenerateCombinations(List<MahjongTile> handTiles, int count)
    {
        if (count == 0)
        {
            yield return new List<MahjongTile>();
            yield break;
        }
        
        if (count > handTiles.Count)
            yield break;
        
        if (count == handTiles.Count)
        {
            yield return new List<MahjongTile>(handTiles);
            yield break;
        }
        
        // 递归生成组合
        for (int i = 0; i <= handTiles.Count - count; i++)
        {
            var first = handTiles[i];
            var remaining = handTiles.Skip(i + 1).ToList();
            
            foreach (var combo in GenerateCombinations(remaining, count - 1))
            {
                var result = new List<MahjongTile> { first };
                result.AddRange(combo);
                yield return result;
            }
        }
    }
    
    /// <summary>
    /// 快速预检查：检查手牌是否可能符合规则（基于类型和值的过滤）
    /// </summary>
    private static bool QuickPreCheck(F8Framework.F8ExcelDataClass.RulesItem rule, List<MahjongTile> handTiles)
    {
        if (rule == null || handTiles == null) return false;
        
        var allowedTypes = ParseAllowedTypes(rule.AllowedTypes);
        var allowedValues = ParseAllowedValues(rule.AllowedValues);
        
        // 检查手牌中是否有足够的牌符合规则的类型和值要求
        var matchingTiles = handTiles.Where(t => 
            allowedTypes.Contains(t.Config.Type) && 
            allowedValues.Contains(t.Config.Value)).ToList();
        
        // 如果符合类型和值的牌数量少于规则要求的数量，无法匹配
        return matchingTiles.Count >= rule.RequiredCount;
    }
    
    /// <summary>
    /// 检查是否能从手牌中选出符合规则的牌
    /// </summary>
    private static bool CanMatchRuleFromHand(F8Framework.F8ExcelDataClass.RulesItem rule, List<MahjongTile> handTiles)
    {
        if (rule == null || handTiles == null) return false;
        
        // 如果手牌数量少于规则要求的数量，无法匹配
        if (handTiles.Count < rule.RequiredCount) return false;
        
        // 快速预检查：过滤明显不符合的规则
        if (!QuickPreCheck(rule, handTiles)) return false;
        
        // 如果手牌数量刚好等于规则要求的数量，直接检查
        if (handTiles.Count == rule.RequiredCount)
        {
            return MatchRule(rule, handTiles);
        }
        
        // 从手牌中生成所有可能的组合（选出RequiredCount张牌）
        // 优化：只对符合类型和值的牌生成组合
        var allowedTypes = ParseAllowedTypes(rule.AllowedTypes);
        var allowedValues = ParseAllowedValues(rule.AllowedValues);
        var candidateTiles = handTiles.Where(t => 
            allowedTypes.Contains(t.Config.Type) && 
            allowedValues.Contains(t.Config.Value)).ToList();
        
        // 如果候选牌数量刚好等于规则要求的数量，直接检查
        if (candidateTiles.Count == rule.RequiredCount)
        {
            return MatchRule(rule, candidateTiles);
        }
        
        // 从候选牌中生成所有可能的组合
        foreach (var combination in GenerateCombinations(candidateTiles, rule.RequiredCount))
        {
            if (MatchRule(rule, combination))
            {
                return true;
            }
        }
        
        return false;
    }

    /// <summary>
    /// Evaluate 并返回得分最高的 RulesItem（从手牌中任意选出符合规则的牌）
    /// </summary>
    public static F8Framework.F8ExcelDataClass.RulesItem EvaluateBestRule(List<MahjongTile> handTiles)
    {
        if (handTiles == null || handTiles.Count == 0) return null;
        
        var rules = FF8.Config.GetRules().Values.ToList();
        F8Framework.F8ExcelDataClass.RulesItem best = null;
        int bestScore = int.MinValue;
        
        foreach (var rule in rules)
        {
            // 检查是否能从手牌中选出符合规则的牌
            if (CanMatchRuleFromHand(rule, handTiles))
            {
                int score = rule.ScoreBase + rule.ScoreBonus;
                if (score > bestScore)
                {
                    bestScore = score;
                    best = rule;
                }
            }
        }
        
        return best;
    }
}
